home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-08-21 | 12.5 KB | 285 lines | [TEXT/CWIE] |
- Documentation for DebugNew.cp
- =============================
-
- Date: August 21, 1998
- Author: Dan Podwall
- Maintenance: John C. Daub
-
- Change Notes:
- `````````````
-
- Pro 4 release:
- - Support for array new and array delete added (MW03205, MW06521).
- This also added a check to ensure calls to new/delete and
- new[]/delete[] match. If you have a custom error handler, you
- may wish to update it to support dbgnewMismatchedNewDelete
- and the updated text for dbgnewBadHeader.
-
- This support also attempts to contend with possible compiler-inserted
- padding (as is done by MW C/C++ for arrays of C++ objects allocated
- via new[]).
-
- Furthermore, any calls to DebugNewDoAllocate and DebugNewDoFree
- will probably need to be updated. Both functions now accept a
- bool is_array as argument (to support the above functionality).
-
- - Updated references to runtime libraries in docs (MW01208)
-
- - Fixed a bug in DebugNewReportLeaks that could case an incorrect
- number of leaks to be reported (MW02460, MW02750)
-
- - DebugNew.cp should now compile cleanly and generate no warnings
- (MW05838). Implicit arithmetic conversions may still exist, however.
-
-
- CW/10 release:
- - Added support for class-specific operator new/delete
-
- - With leak-checking enabled, the block list is kept
- in a hash table instead of a linked list to speed up
- searching for blocks and reduce the perfomance impact
- of leak checking.
-
- - Added DebugNewForgetLeaks(). Use this to eliminate
- extraneous leak reports due to memory that is allocated
- at program startup and never freed. Helpful with PowerPlant
- applications.
-
- - Added DEBUG_NEW_IMPLEMENTATION so you can specify the
- source file implementing global operators new/delete
- without having to modify this file. Typical usage is
- to define this macro in your prefix file, e.g.
- #define DEBUG_NEW_IMPLEMENTATION "MyNewAndDelete.cp"
-
- - Added DEBUG_NEW_NO_GLOBAL_OPERATORS macro so you can prevent
- DebugNew from defining global operators new/delete. Define
- this if you need to use your own global new/delete operators
- but still want to use DebugNew. These operators should call
- DebugNewDoAllocate and DebugNewDoFree when DebugNew is active.
- If you use leak checking, then you must also implement
- operator new(size_t size, const char*, int). Use the
- file New.cp in the MacOS Support:Libraries:Runtime:Common Sources:
- folder as an example.
-
- - DebugNewReportLeaks() returns the number of leaks found.
-
- - Updated for CW10 runtime libraries.
-
- CW/6 release:
- - Modifed source to work with new C++ runtime library.
- - Updated documentation
-
- CW/4 release:
- - Fixed compiler warnings
- - Added gDebugNewFlags, dnDontFreeBlocks, with associated support
- code and diagnostic messages. See the "Changing runtime behavior"
- section for more information.
- - Removed obsolete array support, will re-implement when we
- have operator new[] and operator delete[].
- - Changed default error reporting to DebugStr68k, so the same method
- is used on both 68K and PowerPC. (DebugStr68k always passes messages
- to Macsbug on PPC, DebugStr doesn't.)
-
- Introduction
- ````````````
- The DebugNew package provides a debugging layer over the standard operators
- new, new[], delete, and delete[]. It can help to diagnose common errors
- associated with dynamically allocated memory.
-
- It provides the following services:
-
- - Zaps newly allocated and free blocks with bad values to detect uses
- of uninitialized or deallocated memory.
-
- - Addresses of blocks to be freed are checked to see if they are within
- the application heap.
-
- - Tags allocated blocks to detect double freeing, freeing unknown
- blocks, and overwriting past the end of a block.
-
- - A counter is incremented on allocations and decremented on frees.
- A warning is generated if there are more frees than allocs. You
- can inspect the counter as a crude check to see if any memory has
- leaked.
-
- - Tracks the current number of bytes allocated via operator new
- and the maximum number of bytes ever allocated. Useful for
- tuning memory management and determining a good size memory
- pool to pre-allocate at program startup.
-
- - Optionally tracks memory allocations and can report memory leaks.
- The source file and line is tracked for each allocation, and
- the list of allocated blocks can be dumped to a text file. Full use
- of this feature requires using the macro NEW instead of new in your
- source code.
-
- - Optionally zaps and prevents reuse of freed blocks. This can help
- catch uses of dangling pointers.
-
- Using DebugNew, basic level
- ```````````````````````````
- To get the basic level of checking, all you need to do is add it your project.
- The DebugNew source is located inside the "MacOS Support:Libraries:DebugNew:"
- folder. Just go to that folder and add DebugNew.cp to your project. Make sure
- you do not have New.cp in your project -- you should just have MSL Runtime68K.lib
- for 68K programs or MSL RuntimePPC.lib for PPC programs.
-
- At link time, you will get some linker warnings because DebugNew is overriding
- some runtime library routines. You can get rid of this by enabling "Supress
- warning messages" under the linker preferences.
-
- Doing this gives you all the above features except for full leak checking.
-
- Enabling memory leak checking
- `````````````````````````````
- To enable full leak checking, you must include DebugNew.h in every source
- file you want checked, or just make sure your project prefix includes it.
- Insert the line "#define DEBUG_NEW 2" either in your prefix, or add it
- to the DebugNew.h header.
-
- Every usage of global operator new must be changed to use the macro NEW.
- For example, change:
-
- MyObject* obj = new MyObject;
-
- to:
-
- MyObject* obj = NEW MyObject;
-
- It is possible to "#define new NEW" in your prefix to avoid inserting
- NEW throughout your code. However this can be dangerous as the preprocessor
- is smart but not intelligent and could replace something you do not want
- replaced. It is best to replace each use of the global operator new to
- use the macro NEW. Use the "#define new NEW" trick at your own risk.
-
- When leak checking is enabled, NEW expands to new(__FILE__,__LINE__). This
- is an overloaded form of operator new. When leak checking is disabled,
- NEW simply expands to new. Again, when leak checking is off, this
- expands to the normal operator new, so you can leave this in your
- final code and there is absolutely no overhead.
-
- If leak checking is enabled and the standard new is called, the block is
- still tracked, but the leak report will be missing source file and line
- information for that block. So, you could enable leak checking without
- using NEW. However, the information you get won't be useful enough to
- warrant the overhead.
-
- The NEW macro (as of the Pro 4 revision of DebugNew) can be used when
- allocating C++ arrays. In fact, DebugNew does attempt to catch use
- of delete[] on a new block, or delete on a new[] block. One caveat for
- this support is that the compiler may insert its own header on the
- pointer (in addition to the DebugNew BlockHeader). This compiler header
- is used to store the size of an array element and the number of array
- elements (used internally by the compiler and runtimes. See the Runtime
- Common source NMWException.cp for more details). DebugNew attempts to
- contend with this potential for compiler padding (GetHeader()), but it
- might not be 100% fool-proof (see the comments in GetHeader() for
- more details). If you fail for this reason, it may be wise to examine
- the memory just before your pointer to see what's there, coupled with
- an examination of how your compiler/runtime work for array allocations.
-
- Nothing special needs to be done when freeing objects. Just use the normal
- operator delete (or delete[]).
-
- Since the leak report uses stdio to write a text file, you must include
- the ANSI C library in your project.
-
- Disabling DebugNew
- ``````````````````
- If you are using the basic level of checking, and don't use the NEW macro,
- just remove DebugNew.cp from your project. Or, you can just put
- "#define DEBUG_NEW 0" in your prefix. The result is the same.
-
- If you are using NEW, you must continue to include DebugNew.h in your source.
- Just put "#define DEBUG_NEW 0" in your prefix or at the top of DebugNew.h.
-
- Error Reporting
- ```````````````
- Errors are reported in two ways. When a validation check occurs at runtime,
- an error handler routine is called. The default routine just issues a DebugStr()
- call with a diagnostic message. If you prefer different behavior, you can
- provide your own error handler by calling DebugNewSetErrorHandler(). Validation
- errors occur when operator delete is called, or when your code calls
- DebugNewValidatePtr() or DebugNewValidateAllBlocks().
-
- Memory leaks are reported via the file "leaks.log". This file is written to the
- application's directory whenever DebugNewReportLeaks() is called. One possible
- approach is to call it as the last statement in main(), before your application
- exits.
-
- Changing runtime behavior
- `````````````````````````
-
- The behavior controlled by the DEBUG_NEW macro (off, basic, leaks) is determined
- at compile time, since appropriate support must be compiled into your code, or
- removed from your code when disabling DebugNew.
-
- When DebugNew is enabled, the gDebugNewFlags global contains flags that you
- can set to change DebugNew's behavior. By default, gDebugNewFlags is set to
- dnCheckBlocksInApplZone, meaning by default all valid blocks must be within
- the application zone. You can set the dnDontFreeBlocks flag (or any flag)
- as follows:
-
- gDebugNewFlags |= dnDontFreeBlocks; // set flag
- gDebugNewFlags &= ~dnDontFreeBlocks; // clear flag
-
- When the dnDontFreeBlocks flag is set, operator delete will not actually
- release memory, but it will mark the block as freed and zap the contents. Keep
- in mind that in the normal situation, freed memory may be reallocated on
- subsequent calls to operator new. So when you have a dangling pointer,
- it may point either to a free block or to an allocated block that
- doesn't have the data you think it does. Subtle and hard to find bugs
- may result.
-
- With only basic checking enabled, setting dnDontFreeBlocks may increase
- the likelihood that you can catch a use of a dangling pointer, since
- you will see bad data quickly, and DebugNewValidatePtr will give an
- error. This is especially true if you use a dangling pointer to fetch
- another pointer.
-
- The dnDontFreeBlocks flag is most useful when leak checking is also
- enabled. In that case, freed blocks are also maintained on the block list.
- If your program writes through a dangling pointer, the next call to
- DebugNewValidateAllBlocks will find and signal the error.
-
- Note that the dnDontFreeBlocks has a major impact on memory usage.
- Since memory is not freed, your memory requirements will go up while
- the flag is set. As with leak checking, the intent is that you would
- only use this feature during intense debugging sessions when that
- is not an issue.
-
- When the dnCheckBlocksInApplZone flag is set, any action that checks
- a block's status (just about anything in DebugNew will do this) will first
- check to ensure the block is within the application's heap. If it is
- not, it will return a BlockStatus_t of blockPtrOutOfRange.
-
- Limitations
- ```````````
- - By default, DebugNew only works for the global operator new. However,
- if your class-specific operator new calls the global operator new, then
- those allocations will be tracked.
-
- - DebugNew does not attempt to do anything when an allocation fails.
- That is what set_new_handler() is for.
-
- Overhead
- ````````
- Both the basic checking and memory leak checking add overhead to your program. You
- generally would only enable it for internal testing.
-
- Basic checking adds 12 bytes to each allocated block, and slows down each new/delete
- only slightly.
-
- Leak checking increases the per block overhead to 24 bytes. There is also
- the overhead of finding and removing each block from the block list
- when it is deleted. The memory and time hit will be noticable on moderate to
- large programs. Leak testing should generally only be enabled periodically to
- clean up leaks, and then turned off again.
-
- Any use of padding by the compiler (e.g. in an array of C++ objects allocated
- via new[]) does affect the stored and possibly reported size of a block.
- DebugNewGetPtrSize() compensates for padding, so it should always return the
- proper size of the block. When generating the leaks.log however, the size
- of the pointer plus any compiler padding is reported. But to help you identify
- and compensate, the leaks.log should also report the size of the compiler
- padding, if any.